﻿#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QMouseEvent>
#include <QMessageBox>
#include "control.h"
#include "computer.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget) {
    ui->setupUi(this);
    init();
}

Widget::~Widget() {
    _thread.exit();
    _thread.wait();
    // 释放申请内存
    delete _pCtrl;
    delete _pCom;
    while(!theAllSteps.empty()) {
        Step *step = theAllSteps.last();
        theAllSteps.removeLast();
        delete step;
    }
    delete ui;
}

void Widget::init() {
    // 初始化相关变量
    _selectId = -1;
    _isRedTurn = true;
    _pLastMoveChess = nullptr;
    // 初始化棋子和棋盘
    for(int i = 0; i < 32; ++i) {
        _s[i].init(i);
    }
    // 构造棋子控制类
    this->_pCtrl = new Control(_isRedTurn);
    // 构造电脑走棋类
    this->_pCom = new Computer(_s, _isRedTurn);
    connect(this, SIGNAL(startComputerSignal()), _pCom, SLOT(startComputerSlot()));
    connect(_pCom, SIGNAL(sendComputerBestStep(Step *)), this, SLOT(recvComputerBestStep(Step *)));
    connect(&redTimer, SIGNAL(timeout()), this, SLOT(redTimerSlot()));
    connect(&blackTimer, SIGNAL(timeout()), this, SLOT(blackTimerSlot()));
    // 启动线程
    _thread.start();
    _pCom->moveToThread(&_thread);
    this->setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint);    // 禁用最大化按钮
    this->setFixedSize(this->width(), this->height());                      // 禁止改变窗口大小
}

// 绘图响应事件
void Widget::paintEvent(QPaintEvent *event) {
    _painter.begin(this);
    int d = ChessPiece::r * 2;
    _painter.setPen(QPen(QColor(220, 220, 220)));
    // 画10条横线
    for(int i = 1; i <= 10; ++i) {
        _painter.drawLine(QPoint(d, i * d), QPoint(9 * d, i * d));
    }
    // 画9条竖线
    for(int j = 1; j <= 9; ++j) {
        if(j == 1 || j == 9) {
            _painter.drawLine(QPoint(j * d, d), QPoint(j * d, 10 * d));
        } else {
            _painter.drawLine(QPoint(j * d, d), QPoint(j * d, 5 * d));
            _painter.drawLine(QPoint(j * d, 6 * d), QPoint(j * d, 10 * d));
        }
    }
    // 画九宫格
    _painter.drawLine(QPoint(4 * d, d), QPoint(6 * d, 3 * d));
    _painter.drawLine(QPoint(6 * d, d), QPoint(4 * d, 3 * d));
    _painter.drawLine(QPoint(4 * d, 8 * d), QPoint(6 * d, 10 * d));
    _painter.drawLine(QPoint(6 * d, 8 * d), QPoint(4 * d, 10 * d));
    // 画棋子
    for(int i = 0; i < 32; ++i) {
        drawChess(_painter, i);
    }
    // 绘制最近一次移动棋子的外框
    if(_pLastMoveChess) {
        QPoint center = getCenter(_pLastMoveChess->_id);
        int r = ChessPiece::r;
        QRect rect = QRect(center.x() - r, center.y() - r, r * 2, r * 2);
        // 开始绘制
        _painter.setPen(QPen(QColor(50, 255, 255), 1.5, Qt::DashLine));
        _painter.drawLine(QPoint(rect.x(), rect.y()), QPoint(rect.x(), rect.y() + rect.height()));
        _painter.drawLine(QPoint(rect.x(), rect.y()), QPoint(rect.x() + rect.width(), rect.y()));
        _painter.drawLine(QPoint(rect.x(), rect.y() + rect.height()), QPoint(rect.x() + rect.width(), rect.y() + rect.height()));
        _painter.drawLine(QPoint(rect.x() + rect.width(), rect.y()), QPoint(rect.x() + rect.width(), rect.y() + rect.height()));
    }
    _painter.end();
}

// 鼠标点击响应事件
void Widget::mousePressEvent(QMouseEvent *event) {
    int row = 0, col = 0;
    int result = getRowCol(event->pos(), row, col);
    if(!result) {
        return;
    }
    // 获取所给行列上是否有棋子
    int clickId = -1;
    clickId = _pCtrl->isExistChess(_s, row, col);
    // 点击棋子的颜色必须符合当前次序
    if(_selectId  == -1 && clickId != -1 && _s[clickId]._isRed != _isRedTurn) {
        return;
    }
    // 人工走棋
    personMove(clickId, row, col);
    // 判断黑色一方将是否死亡
    if(true == judgeBlackState()) {
        return;
    }
    // 电脑下棋
    if(!_isRedTurn) {
        // 发送信号,电脑计算走棋
        emit startComputerSignal();
    }
}

// 画棋子
void Widget::drawChess(QPainter &painter, qint8 id) {
    // 如果棋子被吃掉,将不再绘制
    if(_s[id]._isDead) {
        return;
    }
    QPoint center = getCenter(id);
    int r = ChessPiece::r;
    QRect rect = QRect(center.x() - r, center.y() - r, r * 2, r * 2);
    // 如果棋子被选中
    if(id == _selectId) {
        painter.setBrush(Qt::gray);
    } else {
        painter.setBrush(Qt::yellow);
    }
    // 设置反锯齿
    painter.setRenderHint(QPainter::Antialiasing, true);
    // 设置画笔
    painter.setPen(QPen(Qt::red, 1.5));
    if(!_s[id]._isRed) {
        painter.setPen(QPen(Qt::black, 1.5));
    }
    painter.drawEllipse(center, r, r);
    // 设置字体
    QFont font("Microsoft YaHei", r, 100, false);
    painter.setFont(font);
    painter.drawText(rect, _s[id].getText(), QTextOption(Qt::AlignCenter));
}

// 获取棋子中心坐标
QPoint Widget::getCenter(qint8 id) {
    QPoint ret;
    ret.rx() = (_s[id]._col + 1) * ChessPiece::r * 2;
    ret.ry() = (_s[id]._row + 1) * ChessPiece::r * 2;
    return ret;
}

// 获取点击时鼠标坐标对应的行和列
bool Widget::getRowCol(QPoint pt, int &row, int &col) {
    int r = ChessPiece::r;
    if(pt.x() < r || pt.x() > 19 * r || pt.y() < r || pt.y() > 21 * r) {
        return false;
    } else {
        row = (pt.y() - r) / (2 * r);
        col = (pt.x() - r) / (2 * r);
        return true;
    }
}

// 人工走棋
void Widget::personMove(qint8 id, qint8 row, qint8 col) {
    // 判断当前是否已经选中棋子
    if(_selectId == -1) {
        if(id != -1) {
            _selectId = id;
        }
    } else {
        // 是否可以走
        if(_pCtrl->canMove(_s, true, _selectId, row, col, id)) {
            theAllSteps.append(_pCtrl->saveStep(_s, _selectId, id, row, col));
            _pCtrl->moveChess(_s, _selectId, id, row, col);
            reverseNowLabel();
            _selectId = -1;
            _pLastMoveChess = _s + id;
            // 禁用先手按钮
            ui->firstStepBtn->setEnabled(false);
            // 关闭红方定时器，重置黑色定时器
            redTimer.stop();
            initBlackTimerAndLcd();
        }
    }
    update();
}

// 悔一步棋
void Widget::regretSingleStep(short stepNums) {
    // 取消选中
    _selectId = -1;
    for(int i = 0; i < stepNums; ++i) {
        Step *step = theAllSteps.last();
        theAllSteps.removeLast();
        _pCtrl->moveChess(_s, step->_moveId, step->_killId, step->_rowFrom, step->_colFrom);
        _pCtrl->reSaveChess(_s, step->_killId);
        delete step;
    }
}

// 修改当前NowLabel的内容
void Widget::reverseNowLabel() {
    if(_isRedTurn) {
        ui->nowLabel->setStyleSheet("QLabel {color: rgb(250, 80, 80); background-color: rgb(255, 255, 255);}");
        ui->nowLabel->setText(QString(" 红色一方"));
    } else {
        ui->nowLabel->setStyleSheet("QLabel {color: rgb(50, 50, 50); background-color: rgb(255, 255, 255);}");
        ui->nowLabel->setText(QString(" 黑色一方"));
    }
}

// 判断当前红色一方状态
bool Widget::judgeRedState() {
    if(_s[20]._isDead) {
        QMessageBox::StandardButton reply;
        reply = QMessageBox::critical(this, QString("温馨提示"),
                                      QString("黑色一方赢, 再来一局？"),
                                      QMessageBox::Yes | QMessageBox::No);
        return true;
    }
    return false;
}

// 判断当前黑色一方状态
bool Widget::judgeBlackState() {
    if(_s[4]._isDead) {
        QMessageBox::StandardButton reply;
        reply = QMessageBox::critical(this, QString("温馨提示"),
                                      QString("红色一方赢, 再来一局？"),
                                      QMessageBox::Yes | QMessageBox::No);
        return true;
    }
    return false;
}

// 重置红色方定时器和LcdNumber
void Widget::initRedTimerAndLcd() {
    ui->redLcdNumber->display(0);
    redTimer.start(1000);
}

// 重置黑色方定时器和LcdNumber
void Widget::initBlackTimerAndLcd() {
    ui->blackLcdNumber->display(0);
    blackTimer.start(1000);
}

// 打印棋谱
void Widget::on_saveStepsBtn_clicked() {
    if(theAllSteps.empty()) {
        return;
    }
    QTime time = QTime::currentTime();
    QFile file(time.toString().replace(QChar(':'), QChar('_')) + ".txt");
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { //文件不存在会创建文件
        qDebug() << file.errorString();
    } else {
        for(Step *step : theAllSteps) {
            QString name = step->_moveId < 16 ? "黑色一方" : "红色一方";
            QString str = name + QString("%1 从 (%2,%3) 到 (%4,%5)\n")
                          .arg(_s[step->_moveId].getText())
                          .arg(step->_rowFrom)
                          .arg(step->_colFrom)
                          .arg(step->_rowTo)
                          .arg(step->_colTo)
                          ;
            file.write(str.toUtf8());
        }
    }
    file.close();
}

// 我方先手
void Widget::on_firstStepBtn_clicked() {
}

// 悔棋
void Widget::on_regretBtn_clicked() {
    if(theAllSteps.count() > 0) {
        short backNums = theAllSteps.count() > 1 ? 2 : 1;
        regretSingleStep(backNums);
        update();
    } else {
        ui->firstStepBtn->setEnabled(true);
    }
}

// 接受计算类的最优路径
void Widget::recvComputerBestStep(Step *step) {
    Step *bestStep  = step;
    if(!bestStep) {
    } else {
        _pCtrl->moveChess(_s, bestStep);
        _pLastMoveChess = _s + step->_moveId;
        reverseNowLabel();
        // 关闭黑方定时器，重置红方定时器
        blackTimer.stop();
        initRedTimerAndLcd();
        theAllSteps.append(bestStep);
    }
    // 判断红色一方将是否死亡
    judgeRedState();
    update();
}

// 红方定时器溢出槽函数
void Widget::redTimerSlot() {
    int num = ui->redLcdNumber->value();
    ui->redLcdNumber->display(num + 1);
}

// 黑方定时器溢出槽函数
void Widget::blackTimerSlot() {
    int num = ui->blackLcdNumber->value();
    ui->blackLcdNumber->display(num + 1);
}
